// Copyright 2017 Baidu Inc. All Rights Reserved.
// Author: Su Hao (suhao@baidu.com)
//
// Description: baidu_util_list

#include "baidu_util_list.h"
#include <stdio.h>
#include <stdlib.h>
#include "heap_monitor.h"

typedef struct _bu_node {
    void*               _data;
    struct _bu_node*    _next;
} bu_node_t;

static bu_node_t* baidu_util_list_node_create(void* data) {
    bu_node_t* node = (bu_node_t*)MALLOC(sizeof(bu_node_t), CA);

    if (node) {
        node->_data = data;
        node->_next = NULL;
    }

    return node;
}

bu_list_t baidu_util_list_create(void) {
    return (bu_list_t)baidu_util_list_node_create(NULL);
}

int baidu_util_list_append(bu_list_t list, void* data) {
    bu_node_t* q = (bu_node_t*)list;
    bu_node_t* p;

    if (q == NULL) {
        return BU_ERR_INVALID_PARAMETER;
    }

    p = q->_next;

    while (p) {
        if (p->_data == data) {
            return BU_ERR_NODE_EXISTS;
        }

        q = p;
        p = p->_next;
    }

    if (q->_data != data) {
        p = baidu_util_list_node_create(data);

        if (p == NULL) {
            return BU_ERR_MEMORY_OVERLOW;
        }

        q->_next = p;
    }

    return BU_NO_ERR;
}

int baidu_util_list_is_empty(bu_list_t list) {
    bu_node_t* q = (bu_node_t*)list;
    return (q != NULL && q->_next != NULL) ? 0 : 1;
}

void* baidu_util_list_get(bu_list_t list, int index) {
    void* rs = NULL;
    bu_node_t* q = (bu_node_t*)list;
    bu_node_t* p = q ? q->_next : NULL;

    while (p && index > 0) {
        q = p;
        p = p->_next;
        index--;
    }

    if (index == 0 && p && q) {
        rs = p->_data;
    }

    return rs;
}


void* baidu_util_list_remove(bu_list_t list, int index) {
    void* rs = NULL;
    bu_node_t* q = (bu_node_t*)list;
    bu_node_t* p = q ? q->_next : NULL;

    while (p && index > 0) {
        q = p;
        p = p->_next;
        index--;
    }

    if (index == 0 && p && q) {
        rs = p->_data;
        q->_next = p->_next;
        FREE(p);
    }

    return rs;
}

int baidu_util_list_destroy(bu_list_t list) {
    bu_node_t* p = (bu_node_t*)list, *q;

    while (p) {
        q = p;
        p = q->_next;
        FREE(q);
    }

    return 0;
}
